/*
 * Copyright (c) Huawei Device Co., Ltd. 2024. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ef_dodf.h"

#include "der_parser.h"
#include "loghelper.h"

namespace OHOS {
namespace SE {
// reference: GlobalPlatform Device Technology Secyre Element Access Control Spec.
const std::string GP_AC_OID = "1.2.840.114283.200.1.1";
const uint8_t TAG_DODF_DATA = 0xA1;
const uint8_t TAG_SUB_CLASS = 0xA0;
const uint8_t TAG_OID_GP = 0xA1;

EfDodf::EfDodf() : EfParser()
{
}

EfDodf::~EfDodf()
{
}

std::vector<uint8_t> EfDodf::ParseDodfFileData(const std::vector<uint8_t> &dodfData)
{
    std::shared_ptr<DerParser> der = std::make_shared<DerParser>(dodfData);
    while (!der->IsParsingEnd()) {
        if (der->GetTlvType() == TAG_DODF_DATA) {
            // skip data of tag 0x30 twice
            der->GetTlvDataLength(ASN1_SEQUENCE);
            der->SkipTlvData();
            der->GetTlvDataLength(ASN1_SEQUENCE);
            der->SkipTlvData();
            uint8_t objectType = der->GetTlvType();
            if (objectType == TAG_SUB_CLASS) {
                der->SkipTlvData();
                objectType = der->GetTlvType();
            }
            if (objectType != TAG_OID_GP) {
                ErrorLog("dodf data has no filed TAG_OID_GP!!!");
                return std::vector<uint8_t>();
            }
            der->GetTlvDataLength(ASN1_SEQUENCE);
            uint8_t currentIndex;
            uint8_t tlvDataLength;
            der->GetParsingStatus(currentIndex, tlvDataLength);
            if (der->ParseDodfOid() != GP_AC_OID) {
                der->RecoverParsingStatus(currentIndex, tlvDataLength);
                der->SkipTlvData();
            } else {
                return der->ParseEfPath();
            }
        } else {
            der->SkipTlvData();
        }
    }
    return std::vector<uint8_t>();
}

std::vector<uint8_t> EfDodf::ReadDodfFileByPath(const std::vector<uint8_t> &dodfPath)
{
    InfoLog("Parsing DODF file by path.");

    uint16_t rspApdu = 0;
    if (!ReadFileByPath(dodfPath, rspApdu)) {
        ErrorLog("fail to read dodf file, rspApdu[%{public}x]", rspApdu);
        return std::vector<uint8_t>();
    }

    std::vector<uint8_t> dodfFileData = ReadFileByDataSize(0, -1);
    return ParseDodfFileData(dodfFileData);
}
}  // namespace SE
}  // namespace OHOS
